package pl.darbat.incomecalc.math;

import java.util.HashMap;

import pl.darbat.incomecalc.Debug;
import pl.darbat.incomecalc.TaxActivity;

import android.content.Context;
import android.util.Log;

public class ReverseTaxCounter {
	private static final int MAXITER = 30;
	private static final double PRECISION = 0.001;
	
	private TaxCounter mTaxCounter;
	private Context mContext;
	private double mIncomeToReverse;
	private double mReversedIncome;
	private static final String TAG = "ReverseTaxCounter";
	private HashMap<Double,Double> mStoredResults;

	public ReverseTaxCounter(Context context) {
		mContext = context;
		mStoredResults = new HashMap<Double,Double>();
	}

	public double estimateIncomeBrutto(TaxCounter taxCounter, double incomeNetto) {
		mTaxCounter = taxCounter;
		mIncomeToReverse = incomeNetto;
		mReversedIncome = bisect(1.1 * incomeNetto, 1.6 * incomeNetto);

		return mReversedIncome;
	}
	
	//Numeric estimation of function argument - Bisection algorithm

	private double fun(double arg) {
		
		if(mStoredResults.containsKey(arg)){
			return mStoredResults.get(arg);
		} else {
			double result = mTaxCounter.countIncomeNetto(arg, true);
			mStoredResults.put(arg, result);
			return result;
		}
	}

	private boolean check(double result) {
		double delta = mIncomeToReverse - result;
		if(Debug.REVERSETAXCOUNTER) Log.v(TAG,"result:" + result + "delta: " + delta + "netto: " + mIncomeToReverse);
		if (Math.abs(delta) < PRECISION) {
			return true;
		} else {
			return false;
		}
	}

	private double bisect(double a, double b) {
		int n;
		double c = 0;
		mStoredResults.clear();
		for (n = 0; n < MAXITER; n++) {
			c = (a + b) / 2.0;
			if(Debug.REVERSETAXCOUNTER) Log.v(TAG,"reverse:" + mIncomeToReverse + ",     a: " + a + " "+ fun(a) + ",c: " + c + " " + fun(c)+", b: " + b +" "+ fun(b));
			if (check(fun(c))){
				break;
			}
			if (fun(c) < mIncomeToReverse){
				a = c;
			} else {
				b = c;
			}
		}
		if (n == MAXITER) {
			Log.w(TAG, "WARRNING: Not enougth iteration to count argument with precission: " + PRECISION + ", delta: " + (mIncomeToReverse - fun(c)));
		} else {
			Log.v(TAG, "Argument counted with precission: " + PRECISION + ", after iteration: " + n);
		}
		return c;
	}

}
